package Olivia.olivia3d.pick
{
	import Olivia.olivia3d.Olivia3D;
	import Olivia.olivia3d.model.ms3d.MsGroup;
	import Olivia.olivia3d.model.ms3d.TempSimplifyModel;
	import Olivia.olivia3d.vo.Ms3dVo;
	import Olivia.olivia3d.vo.Stage3DVo;
	
	import flash.display.BitmapData;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DTextureFormat;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.display3D.textures.TextureBase;
	import flash.events.EventDispatcher;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	
	public class PickModel extends EventDispatcher
	{
		private static var _self:PickModel;
		public static function get ins():PickModel
		{
			if(!_self){
				_self = new PickModel();
			}
			return _self;
		}
				
		private var _s3dvo:Stage3DVo;
		private var _targetBitmapData:BitmapData;
		private var _rawdata:Vector.<Number>
		
		public function PickModel()
		{
			init();
		}
		
		private function init():void
		{			
			_targetBitmapData = new BitmapData(1,1,false);
			_rawdata = new Vector.<Number>(16);
		}
		
		public function getPickMidx(s3dvo:Stage3DVo):int
		{
			_s3dvo = s3dvo;
			//render models in shadow map
			_s3dvo.context3D.setRenderToBackBuffer();
			_s3dvo.context3D.clear(.3,.3,.3,1);
			for each(var model:Ms3dVo in _s3dvo.models){	
				//create model indexbuffer
				if(!model.initGroupIdx){
					TempSimplifyModel.createMs3dIndexBuffer(s3dvo,model);
					model.initProgram3D(s3dvo.context3D);
				}
				//clear vertex and texture
				_s3dvo.clearBufferAndTexture();
				//upload agal
				upload(model,model.type);			
			}
			_s3dvo.context3D.drawToBitmapData(_targetBitmapData);
			var meshid:uint = _targetBitmapData.getPixel(0, 0);
			if(meshid != 5000268)
				trace(meshid);
			return meshid;
		}
		
		private function upload(model:Ms3dVo, type:int):void
		{
			// TODO Auto Generated method stub
			var vertexes:VertexBuffer3D = _s3dvo.context3D.createVertexBuffer(
				model.vertexData.length/model.dataPerVertex, 
				model.dataPerVertex);
			vertexes.uploadFromVector(
				model.vertexData,
				0,
				model.vertexData.length/model.dataPerVertex);
			//va0 is position
			_s3dvo.context3D.setVertexBufferAt(0, vertexes, 0, Context3DVertexBufferFormat.FLOAT_3);
			
			//set program contants
			setProgramContants(model,type);
			if(type==Ms3dVo.BaseType){
				//agal
				_s3dvo.setAgal(_s3dvo.pickPro3d);
			}else if(type==Ms3dVo.AnimType){
				var bonesVector:Vector.<Number> = model.getBoneVector(5);
				var bones:VertexBuffer3D = _s3dvo.context3D.createVertexBuffer(bonesVector.length/4,4);
				bones.uploadFromVector(
					bonesVector,
					0,
					bonesVector.length/4);
				//va3 is boneid
				_s3dvo.context3D.setVertexBufferAt(3, bones, 0, Context3DVertexBufferFormat.FLOAT_4);
				//get model fps born matrix
				getModelAnimotionMatrix(model);
				//agal
				_s3dvo.setAgal(_s3dvo.pickPro3dAni);
			}
			//render group
			renderGroup(_s3dvo.context3D,model);
		}
		
		private function renderGroup(context3D:Context3D,msvo:Ms3dVo):void
		{
			for each(var g:MsGroup in msvo.groupData){
				context3D.drawTriangles(g.indexBuffer);
			}
		}	
		
		private function getModelAnimotionMatrix(model:Ms3dVo):void
		{
			// TODO Auto Generated method stub
			_s3dvo.context3D.setProgramConstantsFromVector(
				Context3DProgramType.VERTEX,
				4,
				Vector.<Number>([1,2,0,0]));
			_s3dvo.context3D.setProgramConstantsFromVector(
				Context3DProgramType.VERTEX,
				5,
				model.getJointDataForNextFrame());
		}		
		
		private function setProgramContants(model:Ms3dVo,type:int):void
		{
			// TODO Auto Generated method stub	
			//vc
			_s3dvo.context3D.setProgramConstantsFromMatrix(
				Context3DProgramType.VERTEX, 
				0,
				getPickMat(model.position),
				true);
			//fc
			_s3dvo.context3D.setProgramConstantsFromVector(
				Context3DProgramType.FRAGMENT,
				0,
				Vector.<Number>([0, 0, model.msid/255, 0]));
		}
		
		private function getPickMat(pos:Vector3D):Matrix3D
		{
			//world*view
			var reMat:Matrix3D = Olivia3D.ins.mainCamera.getWorldViewMat(pos).clone();
			//append pick project mat
			Olivia3D.ins.mainCamera.projection.copyRawDataTo(_rawdata);
			_rawdata[8] = Olivia3D.ins.main.mouseX/800*2;
			_rawdata[9] = -Olivia3D.ins.main.mouseY/600*2;			
			var pickProMat:Matrix3D = new Matrix3D();
			pickProMat.copyRawDataFrom(_rawdata);
			//*pick project mat
			reMat.append(pickProMat);			
			return reMat;
		}
	}
}